package com.xinziruo.crawl.infrastruture.support.server;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;

/**
 * 
 * @author loudyn
 * 
 */
public class CommandClientHolder {
	private static final ScheduledExecutorService MONITOR = Executors.newSingleThreadScheduledExecutor();
	private static final ConcurrentHashMap<IoSession, CommandClient> HOLDER = new ConcurrentHashMap<IoSession, CommandClient>();
	private static final AttributeKey KEEPALIVE = new AttributeKey(CommandClientHolder.class, "keepalive");

	static {
		monitorKeepalive();
	}

	private static void monitorKeepalive() {
		MONITOR.scheduleAtFixedRate(new Runnable() {

			public void run() {
				List<CommandClient> clients = CommandClientHolder.clientsSnapshot();
				for (CommandClient client : clients) {

					IoSession session = client.getSession();
					if (session.isClosing() || client.isLoseHeartbeat()) {
						CommandClientHolder.remove(session);
					}
				}
			}

		}, 60, 60, TimeUnit.SECONDS);
	}

	/**
	 * 
	 * @param session
	 * @return
	 */
	public static CommandClient get(IoSession session) {
		assertSessionNotNull(session);
		return HOLDER.get(session);
	}

	/**
	 * 
	 * @param session
	 */
	public static void put(IoSession session) {

		assertSessionNotNull(session);
		if(session.containsAttribute(KEEPALIVE)){
			CommandClient client = get(session);
			client.updateHeartbeat();
			return;
		}

		CommandClient newClient = new CommandClient(session);
		HOLDER.put(session, newClient);
		
		session.setAttribute(KEEPALIVE);
		newClient.updateHeartbeat();
	}

	/**
	 * 
	 * @param session
	 */
	public static void remove(IoSession session) {
		assertSessionNotNull(session);
		
		HOLDER.remove(session);
		session.close(true);
	}

	/**
	 * 
	 * @return
	 */
	public static List<CommandClient> clientsSnapshot() {
		return new ArrayList<CommandClient>(HOLDER.values());
	}

	/**
	 * 
	 * @return
	 */
	public static CommandClient[] clientsSnapshotAsArray() {
		return HOLDER.values().toArray(new CommandClient[] {});
	}

	private static void assertSessionNotNull(IoSession session) {
		if (null == session) {
			throw new IllegalArgumentException("session must be not null!");
		}
	}

}
